#include "virtualfs.h"

#ifdef Q_OS_WIN32
#define slash "\\"
#else
#define slash "/"
#endif


VirtualFs::VirtualFs() :
    _root("/", "", "", "", true)
{

}


VirtualFs::~VirtualFs()
{
    clear(root());
}



qint64 VirtualFs::clear(VirtualFsObject* vfs_root)
{
    if(!vfs_root) return 0;
    vfs_root->clear();
    return 0;
}


qint64 VirtualFs::folder_indexOf(VirtualFsObject* vfs_root, const QString & name, qint64 from)
{
    for(qint64 i = from; i< vfs_root->size(); ++i)
    {
        if( vfs_root->at(i)->isDir() && vfs_root->at(i)->name() == name )
        {
            return i;
        }
    }
    return -1;
}



qint64 VirtualFs::file_indexOf(VirtualFsObject *vfs_root, const QString & name, qint64 from)
{
    for(qint64 i = from; i< vfs_root->size(); ++i)
    {
        if( !vfs_root->at(i)->isDir() && vfs_root->at(i)->name() == name )
        {
            return i;
        }
    }

    return -1;
}


VirtualFsObject *VirtualFs::createFolder(VirtualFsObject *vfso, const QString & name)
{
    if(name.isEmpty())
        return 0;

    qWarning() << "Create folder " << name;
    mutex.lock();
    if(folder_indexOf(vfso, name) == -1)
    {
        VirtualFsObject *o = new VirtualFsObject();
        o->setName(name);
        o->setRealName(name);
        o->setVirtualWay(vfso->virtualWay() == "/"? "" : vfso->virtualWay() + "/" + vfso->name());
        o->setDirType(true);

        vfso->push_back(o);
        mutex.unlock();
        return o;
    }
    
    mutex.unlock();
    return 0;
}


int VirtualFs::addFolder(QString way, bool recur)
{
    if(way == "/") return -2;
    if(way.isEmpty()) return -3;

    VirtualFsObject *vroot = root();

    QStringList names = way.split("/");
    names.removeFirst();
    names.removeLast();
    qint64 size = names.size()-1, cnt = size;
    VirtualFsObject *p = 0;

    foreach(QString name, names)
    {
        if(name.isEmpty()) {
            qWarning() << "Invalid folder name";
            return -1;
        }

        qWarning() << "cheking for exist .." << name;

        if(recur){

            if((p = createFolder(vroot, name)) == 0)
            {
                mutex.lock();
                int64_t i = folder_indexOf(vroot, name);
                if(i > -1) {
                    p = vroot->at(i);
                    mutex.unlock();
                    qWarning() << "folder exist!";
                } else {
                    mutex.unlock();
                    qWarning() << "Cant create";
                }

            } else
            {
                qWarning() << "creating...";
            }
        } else
        {
            mutex.lock();
            int i = folder_indexOf(vroot, name);
            if(i > -1)
                p = vroot->at(i);
	    mutex.unlock();

            if(i == -1) {
                if(cnt)
                {
                    qWarning() << "cannot enter to " << name << ". Folder not exist!";
                    return -1;
                }else
                {
                    qWarning() << "creating...";
                    p = createFolder(vroot, name);
                }
            }else
            {
                if(!cnt) {
                    qWarning() << "folder exist!";
                    return -2;
                }
            }

        }

        qWarning() << "entering to folder";

        vroot = p;
        cnt--;
    }


    return 0;
}



VirtualFsObject *VirtualFs::createFile(VirtualFsObject *vroot, const QString & realWay, const QString & name, const QString & _realName)
{
    if(name.isEmpty())
        return 0;

    qWarning() << "Creating file " << name;
    mutex.lock();
    if(file_indexOf(vroot, name) == -1)
    {
        VirtualFsObject *o = new VirtualFsObject();
        o->setName(name);
        o->setRealWay(realWay);
        o->setRealName(_realName.length()? _realName : name);
        o->setVirtualWay(vroot->virtualWay() == "/"? "" : vroot->virtualWay() + "/" + vroot->name());
        o->setDirType(false);

        vroot->push_back(o);
        mutex.unlock();
        return o;
    }

    mutex.unlock();
    return 0;
}



int VirtualFs::addFile(const QString & realWay, const QString & virtualWay, const QString & fname, bool recur)
{
    if(fname.isEmpty())
        return -1;

    qDebug() << __FUNCTION__ << virtualWay+fname;
    qDebug() << "realway " <<realWay;

    VirtualFsObject *vroot = root();

    QStringList names = virtualWay.split("/");
    names.removeFirst();

    if(virtualWay.endsWith("/"))
        names.removeLast();
    qint64 p = 0;

    if(recur)
        addFolder(virtualWay, true);

    foreach(QString name, names)
    {
	mutex.lock();
        p = folder_indexOf(vroot, name);
        if(p == -1) {
            mutex.unlock();
            qWarning() << "error entering to folder " << name;
            return -1;
        }

        vroot = vroot->at(p);
        mutex.unlock();
    }

    if(createFile(vroot, realWay, fname) == 0)
    {
        qWarning() << "file" << fname << "exist";
    }else
    {
        qWarning() << "Successfully crated";
        return 0;
    }

    return -1;
}



bool VirtualFs::isFolder( const QString & _folder )
{
    if(_folder == "/") return true;

    return folder(_folder)? true : false;
}


VirtualFsObject* VirtualFs::folder( const QString & _folder )
{
    return folder(root(), _folder);
}


VirtualFsObject* VirtualFs::folder(VirtualFsObject *vroot, const QString & _folder )
{
    QString way = _folder;
    if(way == "/") return vroot;
    if(way.isEmpty() || !way.startsWith("/") || !way.endsWith("/")) return 0;

    QStringList names = _folder.split("/");
    names.removeFirst();
    names.removeLast();
    qint64 p = 0;

    foreach(QString name, names)
    {
        mutex.lock();
        p = folder_indexOf(vroot, name);
        if(p == -1) {
            mutex.unlock();
            qWarning() << "error entering to folder " << name;
            return 0;
        }

        vroot = vroot->at(p);
        mutex.unlock();
    }

    return vroot;
}


bool VirtualFs::isFile( const QString & way )
{
    if(way == "/") return false;
    if(way.endsWith("/")) return false;


    return file(way)? true : false;
}


VirtualFsObject *VirtualFs::file( const QString & file )
{
    QString way = file;
    if(way.isEmpty() || way == "/") return 0;

    VirtualFsObject *vroot = root();

    QStringList names = way.split("/");
    names.removeFirst();
    QString _file = names.last();
    names.removeLast();
    qint64 p = 0;

    foreach(QString name, names)
    {
        mutex.lock();
        p = folder_indexOf(vroot, name);
        if(p == -1) {
            mutex.unlock();
            qWarning() << "error entering to folder " << name;
            return 0;
        }

        vroot = vroot->at(p);
        mutex.unlock();
    }

    mutex.lock();
    p = file_indexOf(vroot, _file);
    if(p == -1) {
	mutex.unlock();
        return 0;
    }
    
    VirtualFsObject *r = vroot->at(p);
    mutex.unlock();

    return r;
}



int VirtualFs::rm( const QString & _file )
{
    if(_file.isEmpty())
        return -1;

    QString f = _file.right( _file.length() - _file.lastIndexOf("/") -1);
    QString fdr = _file.left( _file.lastIndexOf("/")+1 );

    VirtualFsObject *fo = folder(fdr);
    if(!fo) {
        return -1;
    }

    mutex.lock();
    qint64 p = file_indexOf(fo, f);
    if(p == -1) {
        mutex.unlock();
        return -2;
    }


    delete fo->at(p);
    fo->remove(p);
    mutex.unlock();
    
    qWarning() << "successed del";
    return 0;
}


int VirtualFs::rmdir( const QString & dir )
{
    if(dir.isEmpty())
        return -1;

    qWarning() << __FUNCTION__ << dir;
    if(dir == "/") return -1;
    if(!dir.startsWith("/") || !dir.endsWith("/")) return -1;

    QString subf = dir.left( dir.lastIndexOf("/", dir.length()-2) +1 );
    QString name = dir.right( dir.length() - dir.lastIndexOf("/", dir.length()-2) -1);

    name = name.remove(name.length()-1, 1);

    VirtualFsObject *fo = folder(subf), *_f;

    qWarning() << "subf" << subf << name;

    mutex.lock();
    qint64 p = folder_indexOf(fo, name);
    if(p == -1) {
        mutex.unlock();
        return -2;
    }
    mutex.unlock();

    clear( (_f = folder(dir)) );

    if(_f)
        delete _f;
    
    fo->remove(p);
    qWarning() << "successed del";
    return 0;
}



bool VirtualFs::isNameValid(const QString & name)
{
    foreach(const QChar & c, name)
    {
        if( c == '/' ) return false;
    }

    return true;
}


int VirtualFs::rename(const QString & obj, const QString & to)
{
    if(!isNameValid(to)) return -1;

    if(isFile(obj))
    {
        VirtualFsObject *vfso = file(obj);
        vfso->setName(to);
    } else if(isFolder(obj))
    {
        VirtualFsObject *vfso = folder(obj);
        vfso->setName(to);
    } else {
        qWarning() << __FUNCTION__ << "object not exist, nothing for rename";
        return -2;
    }

    return 0;
}


void VirtualFs::dump(VirtualFsObject * root)
{
    qWarning() << "\n\nNEW: size " << root->size();
    for(int i=0; i< root->size(); ++i)
    {
        qWarning() << root->at(i)->name();
        qWarning() << "Folder: " << (bool)root->at(i)->isDir();
        qWarning() << "real wey: " << root->at(i)->realWay();
        qWarning() << "virtual wey: " << root->at(i)->virtualWay();

        if(root->at(i)->isDir())
        {
            dump(root->at(i));
        }
    }
}

